module nade.sound;

import std.file;
import std.string;

import derelict.openal.al;

import nade.vector;


class Source {
	private {
		ALuint			_source;
	}

	this()
	{
		ALenum error;
		alGetError();

		alGenSources(1, &_source);
		if((error = alGetError()) != AL_NO_ERROR) throw new Error(format("Error: alGenSources: %d", error));

		alSourcef(_source, AL_PITCH, 1.0);
		alSourcef(_source, AL_GAIN, 1.0);
		alSourcei(_source, AL_LOOPING, AL_FALSE);
	}

	void play(Sample sample)
	{
		alSourcei(_source, AL_BUFFER, sample._buffer);
		alSourcePlay(_source);
	}

	void position(Vector3 position)
	{
		ALfloat[3] sourcePosition = [ position.x, position.y, position.z ];
		alSourcefv(_source, AL_POSITION, sourcePosition.ptr);
	}

	void velocity(Vector3 velocity)
	{
		ALfloat[3] sourceVelocity = [ velocity.x, velocity.y, velocity.z ];
		alSourcefv(_source, AL_VELOCITY, sourceVelocity.ptr);
	}
}


class Sample {
	private {
		ALuint			_buffer;
		int				_format;
		uint			_frequency;
	}

	this(string path)
	{
		ALenum error;
		alGetError();

		alGenBuffers(1, &_buffer);
		if((error = alGetError()) != AL_NO_ERROR) throw new Error(format("Error: alGenBuffers: %d", error));

		ubyte* file = cast(ubyte*)(read(path).ptr);

		ubyte* fmt = file + 12;
		uint fmtSize = fmt[4] + (fmt[5]<<8) + (fmt[6]<<16) + (fmt[7]<<24);
		uint channels = fmt[10] + (fmt[11]<<8);
		_frequency = fmt[12] + (fmt[13]<<8) + (fmt[14]<<16) + (fmt[15]<<24);
		uint bitsPerSample = fmt[22] + (fmt[23]<<8);

		switch(channels)
		{
			case 1:
			{
				switch(bitsPerSample)
				{
					case 8: _format = AL_FORMAT_MONO8; break;
					case 16: _format = AL_FORMAT_MONO16; break;
					default: assert(false);
				}
				break;
			}
			case 2:
			{
				switch(bitsPerSample)
				{
					case 8: _format = AL_FORMAT_STEREO8; break;
					case 16: _format = AL_FORMAT_STEREO16; break;
					default: assert(false);
				}
				break;
			}
			default:
			{
				assert(false);
			}
		}

		ubyte* data = fmt + fmtSize + 8;
		uint dataSize = data[4] + (data[5]<<8) + (data[6]<<16) + (data[7]<<24);
		alBufferData(_buffer, _format, data + 8, dataSize, _frequency);
	}
}
